/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package coalescent.br;

import com.google.common.collect.ImmutableSet;

import java.math.BigDecimal;

/**
 * Specifies a state space element of an Ancestral Markov Chain (AMC). AMC is defined to be an MC
 * whose transition graph has a <i>single source</i> and a <i>single sink</i> and a single state
 * space that consists of all the elements in the graph. AMC has degenerate probability
 * distributions at both the source and the sink. State space elements have positive transition
 * probability in only one transition. Transitions are identified by an integer index and
 * categorized by types.<p/>
 * It has <i>transition index</i> to identify the transition in a path of the transition graph. It
 * defines a <i>boundary condition</i> that identifies the sink of the transition graph.<p/>
 * Transition probabilities and the boundary probability are also defined.<p/>
 * The design has the following functional requirements: 1) traverse the full transition graph 2)
 * provide the transition probabilities.
 *
 * @param <E> enum representing transition types
 * @param <R> runtime type of this interface
 * @author Susanta Tewari
 * @since 1.3.0
 */
public interface AMCElement<E extends Enum<E>, R extends AMCElement<E, R>> {

    /**
     * Events categorize the transitions.
     *
     * @return all transitionTypes of this AMC element
     */
    public ImmutableSet<E> transitionTypes();

    /**
     * Transitions from this AMC element for the specified event.
     *
     * @param event one of the values returned by {@link #transitionTypes()}
     * @return transitions for {@code event}
     * @throws NullPointerException if {@code event} is {@code null}
     * @throws IllegalArgumentException if {@code event} is not present in {@link #transitionTypes()}
     */
    Iterable<R> transitions(E event);

    /**
     * Computes the transition probability from this element to the specified element {@code transitionElement}.
     * The specified element {@code transitionElement} must be one of the values returned by {@link #transitions(event)}.
     *
     * @param transitionType one of the values returned by {@link #transitionTypes()}
     * @param transitionElement one of the values returned by {@link #transitions(java.lang.Enum event)}
     * @return transition probability from this element to the specified one
     * @throws NullPointerException if any of the parameters is {@code null}
     * @throws IllegalArgumentException if 1) {@code event} is not present in {@link #transitionTypes()} 2) {@code transitionElement}
     * is not present in {@link #transitions(java.lang.Enum event)}
     */
    BigDecimal transitionProb(E transitionType, R transitionElement);

    /**
     * Checks if this element is the sink of the associated transition graph.
     *
     * @return {@code true} this element is the sink; {@code false} otherwise
     */
    boolean isSink();

    /**
     * Returns the probability of the sink of the associated transition graph.
     *
     * @return the probability of the sink
     */
    BigDecimal sinkProbability();

    /**
     * State space elements have positive transition probability in only one transition. Transitions
     * are identified by an integer index. Transition index forms an equivalence relation and in
     * turn helps in making the traversal of the transition graph efficient (transition index based
     * distributed cache).
     *
     * @return the transition index of this element
     */
    int transitionIndex();
}
